{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 第五章 基于数组的序列"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 5.2 低层次数组"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "1字节 = 8位"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "存储地址：计算机用于跟踪信息存储在哪个字节。每个存储字节都和一个作为其地址的唯一数字相关联，这些数字是连续的。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "给定存储地址，检索和存储RAM(Random Access Memory)的运行时间为O(1)。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "编程语言记录标识符（变量名）与所存储的地址之间的联系。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "数组（array）：一组相关变量能够一个接一个地存储在计算机存储器的一块连续区域内。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "编程语言中，变量名与存储地址相联系，而数组是一组变量，每个变量指向的存储地址是挨在一起的，而表示存储地址的数字是连续的，因此可以通过索引+第一个元素的存储地址来访问其他元素，这对数组来说很方便。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Python中的str类是文本数组（array），字符的存储地址是连续的，Python使用16位，即两个字节来存储一个字符，一个字符串的所有字符存储地址连续。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Python使用Unicode来给字符编码，因此每个字符用两个字节存储（Unicode就是如此）。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "1个byte含8个bit，一个bit存储0,1；因此1个byte最大可以存储的十进制数字是255（即二进制11111111），这255个十进制数字用于ASCII编码，以通过数字来表示字符（计算机只能处理数字），这就是ASCII编码，1个byte存储的数字可以表示一个字符，而Unicode需要2个byte存储一个字符，当然能存储的字符也更多，包括通用语言的字符。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "数组中的每一个位置称为单元（cell）。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "数组中的每个单元必须占据相同数量的byte，这允许通过索引值和第一个单元存储地址来计算其他单元的存储地址，从而直接进行访问。访问时间为常量时间，即O(1)。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 5.2.1 引用数组"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "浅拷贝：列表的每一个元素指向相同的存储位置，若每一个元素是不可变的，则没有影响。但若是可变的，如每一个元素都是一个list，那么改变其中一个列表会导致另外一个列表也改变。这时需要深拷贝，创建一个存储地址完全不一样的副本。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "语法`mylist = [0]*8`会创建一个list，所有元素指向一个存储地址中的0，由于0不可变，所以没有什么影响。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "list的方法`extend`会将一个列表的引用复制到列表，相当于浅拷贝到末尾。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Python中的list和tuple都使用引用结构，即list首先存储的是元素的存储地址，然后调用时，先获得元素的存储地址再获得元素，整个过程相当于list引用了一块连续内存中的元素，而不是将元素直接存储在list中。因此会出现两个list指向了同一块内存，改变一个list相当于改变了所引用的这一块内存，这导致另一个list随之改变。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在list的引用问题中，要分析不同的情况，有时两个list引用了同一块连续的内存，有时两个list的各个元素指向同一个地址，这两种情况是不同的，前者可以通过改变一个list来改变另外一个，后者需要每个元素指向的地址存储的元素是可变的。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "引用的好处在于列表每个元素占用内存的大小可能差别很大，会违反数组每个元素占用相同内存的规则，但是用最大元素内存来存储又浪费空间，因此先将所有元素存储在一块内存中，再将64位内存地址（固定为64位）存储在一个数组中，通过数组的索引可以获得相应元素内存地址的存储位置，获得相应元素的内存地址后再访问，即可。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "引用数组每个元素存储地址连续，但是指向的存储地址可能是不连续的。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 5.2.2 Python中的紧凑数组"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "紧凑数组（compact array）：数组每个元素直接存储，而不是引用（引用相当于存储的是所引用元素的内存地址）。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "引用数组占用内存大于紧凑数组，引用数组每个元素都存储64位即8字节的内存地址，无论存储单个元素的对象有多少位，而紧凑数组，如Python中的字符串，每个元素为2个字节即16位。（Unicode字符）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Python的list为什么占内存：引用的元素存储在内存中，又将64位地址存储进list中，比紧凑型多出64位地址存储所需的内存空间。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "array模块的array类可以创建紧凑数组。紧凑数组占用内存少，在计算时的速度也快，在对很多整数进行处理时，可以创建紧凑数组进行存储。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "from array import array\n",
    "\n",
    "primes = array('i', [2, 3, 5, 7, 11, 13, 17, 19])                         ## 先指明元素的类型，'i'表示整数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "因为紧凑数组是直接存储元素，而不是64位存储地址，因此需要通过元素类型来判断一个元素需要多少位的内存。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "有很多数据类型可以选择，但是要是没有想要的，那么array模块不能满足需求，因为不能自定义，这时应该使用ctypes模块。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 5.3 动态数组和摊销"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "一般而言，数组存储在一段连续的内存中，系统可能占用周围的内存，因此数组是不能无限制变大的。Python的str和tuple不存在这个问题，因为他们不可变。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Python的list类是动态数组（dynamic array），创建一个list时，会根据list的长度预留更长的数组，因此list类增添数组很容易。当增加的元素过多，预留的空间也被用完时，才会向系统请求一个新的更大的数组。原来的数组就被回收。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "64\n",
      "80\n",
      "80\n"
     ]
    }
   ],
   "source": [
    "import sys\n",
    "\n",
    "a = []\n",
    "b = [1, 2]\n",
    "c = [[1, 2, 4, 5, 6, 7], [3, 4, 5, 6, 7, 8]]\n",
    "print(sys.getsizeof(a))\n",
    "print(sys.getsizeof(b))\n",
    "print(sys.getsizeof(c))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "空list已经占有64个字节的内存。getsizeof返回list存储64位内存地址的数组所用空间，不包括引用的元素占用的内存。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "list预留内存空间，会使list占用的内存随着元素个数的增加而呈现阶梯式上升，每次上升都是因为预留空间使用完。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在Python中，预留的大小的规律尚不确定，作练习研究，一个元素需要64位即8个字节，4个元素就是32个字节，所以每次请求下一个新的数组后，增加4个元素将不会引起内存变化，再增加一个将会使内存直接增大32个字节，这里不需要考虑引用元素，就单纯研究存储64位2内存地址的数组。实验代码如下："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Length:   0; Size in bytes:   64\n",
      "Length:   1; Size in bytes:   96\n",
      "Length:   2; Size in bytes:   96\n",
      "Length:   3; Size in bytes:   96\n",
      "Length:   4; Size in bytes:   96\n",
      "Length:   5; Size in bytes:  128\n",
      "Length:   6; Size in bytes:  128\n",
      "Length:   7; Size in bytes:  128\n",
      "Length:   8; Size in bytes:  128\n",
      "Length:   9; Size in bytes:  192\n",
      "Length:  10; Size in bytes:  192\n",
      "Length:  11; Size in bytes:  192\n",
      "Length:  12; Size in bytes:  192\n",
      "Length:  13; Size in bytes:  192\n",
      "Length:  14; Size in bytes:  192\n",
      "Length:  15; Size in bytes:  192\n",
      "Length:  16; Size in bytes:  192\n",
      "Length:  17; Size in bytes:  264\n",
      "Length:  18; Size in bytes:  264\n",
      "Length:  19; Size in bytes:  264\n",
      "Length:  20; Size in bytes:  264\n",
      "Length:  21; Size in bytes:  264\n",
      "Length:  22; Size in bytes:  264\n",
      "Length:  23; Size in bytes:  264\n",
      "Length:  24; Size in bytes:  264\n",
      "Length:  25; Size in bytes:  264\n",
      "Length:  26; Size in bytes:  344\n",
      "Length:  27; Size in bytes:  344\n",
      "Length:  28; Size in bytes:  344\n",
      "Length:  29; Size in bytes:  344\n"
     ]
    }
   ],
   "source": [
    "import sys\n",
    "\n",
    "data = []\n",
    "for k in range(30):\n",
    "    a = len(data)\n",
    "    b = sys.getsizeof(data)\n",
    "    print('Length: {0:3d}; Size in bytes: {1:4d}'.format(a, b))\n",
    "    data.append(None)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 5.3.2 动态数组的摊销分析"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "通常来说，动态数组在预留的内存用完后需要创建一个新的数组，新数组可以存储的元素个数是原来的两倍。在添加元素的过程中，如果预留内存没用完，运行时间为常量时间，如果用完了，则需要O(n)。在每一次付出代价之后，可以存储跟原来相同的元素个数的元素，才需要重新付出代价，而付出大代价的个数事实上只是对数次而已，因为元素个数是指数增长的。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "摊销（amortization）、摊销分析（amortization analysis）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> 命题5-1：设S是一个由具有初始大小的动态数组实现的数组，实现策略为：当数组已满时，将此数组大小扩大为原来的2倍。S最初为空，对S连续执行n个增添操作的运行时间为O(n)。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "命题5-1与之前的不同之处在于，之前的时间复杂度是按照一次增添操作来计算的，这里的是按n次来计算的，原因是n次操作中会有操作需要扩充数组，所需时间比不需要扩充数组时要长，使用平均或者摊销分析的方式，可以分析n次操作的总时间。由于每次将数组扩充为原来的两倍，那么从$2^n$到$2^{n+1}$大小的过程中，需要时间$O(2^n)$，假设每次操作需要时间为1，那么这里将$2^n$分给索引为$2^{n-1}+1$到$2^n$的元素，每个元素多分时间2，即每次操作需要时间3，那么就可以忽略扩充数组的时间了，而$3n$仍然是O(n)，因此n次操作需要O(n)时间，但是不能说一次操作，一次操作容易引起误解，同时也不是每次操作都是O(1)，而是摊销后为O(1)。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "为什么会变成n次O(n)：每次扩充新数组为2n时，距离上一次扩充为n/2个元素。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "结论：数组大小几何增长，则每次操作的摊销运行时间仍未O(1)。（一定要强调是`摊销`运行时间）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "几何增长（成倍增长）的优点是摊销运行时间快，缺点是占用空间大，牺牲了空间换来了时间。（但空间复杂度仍然为O(n)）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "可以选用较小的几何增长速度，如1.25，但是这会换来较多的扩充次数，而且只要是倍数，在数组大到一定程度时就可能导致内存空间的浪费。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如果是每次扩充数列都预留k个元素的内存，那么事实上效率较低，但是在空间是更为节省，时间上n次操作需要$O(n^2)$，以预留一个元素为例很容易证明，预留k个也可证明。（这是等差数列增长）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> 命题5-2：对初始为空的动态数组执行连续n个增添操作，若每次调整数组大小时采用固定的增量，则运行时间为$\\Omega(n^2)$。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "等差数列求和有公式，或者提取常数变成1+2+3+...，令$m=n/c$也是一个技巧。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Python的list的底层数组（即存储64位存储地址的数组）是一个动态数组。同时list本身是一个引用数组而不是一个紧凑数组。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 5.4 Python序列类型的效率（list、tuple、dict、str）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 5.4.1 Python的list和tuple类"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "tuple的内存利用率比list高，因为tuple不可变，不需要预留内存空间。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "list和tuple的nonmutating行为效率："
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "操作 | 运行时间 | 原因\n",
    ":-: | :-: | :-:\n",
    "len(data) | O(1) | 实例中存储了长度，直接访问\n",
    "data[j] | O(1) | list和tuple底层是数组，访问元素可直接获得内存地址\n",
    "data.count(value) | O(n) | 显然计算有多少个是需要遍历的\n",
    "data.index(value) | O(k+1) | k为索引，k+1是个数，找到了就停止\n",
    "value in data | O(k+1) | 找到了就停止\n",
    "data1 == data2（包括其他表示大小关系的符号） | O(k+1) | 有不相等就停止\n",
    "data[j:k] | O(k-j+1) | 显然\n",
    "data1 + data2 | O(n1+n2) | 创建了一个新的list或者tuple\n",
    "c\\*data | O(cn) | 创建了一个新的数组 "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "涉及到k的，在最坏的情况下就是n了！！！"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "list和tuple的mutating行为效率："
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "操作 | 运行时间 | 原因\n",
    ":-: | :-: | :-:\n",
    "data[j] = value | O(1) | 改变一个值\n",
    "data.append(value) | O(1)<sup>*</sup> | 摊销运行时间，不过list和tuple动态数组是如何实现的还不知道，不是单纯几何增长\n",
    "data.insert(value) | O(n-k+1)<sup>*</sup> | 摊销运行时间，需要将后面的元素往后移，如果是最坏情况则为O(n)，摊销是考虑是否有足够空间\n",
    "data.pop() | O(1)<sup>*</sup> | 摊销运行时间，但是不明白为什么需要摊销\n",
    "data.pop(k)、del data[k] | O(n-k)<sup>*</sup> | 删掉一个时，需要移动剩下的，保证数组连续\n",
    "data.remove(value) | O(n)<sup>*</sup> | 摊销运行时间，这个不太清楚\n",
    "data1.extend(data2)、data1 += data2 | O(n<inf>2</inf><sup>*</sup>) | 摊销运行时间，相当于append了n<inf>2</inf>个\n",
    "data.reverse() | O(n) | 可以从递归理解\n",
    "data.sort() | O(nlog n) | 最快的排序为O(nlog n)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在list的最开始位置insert元素是最费时的。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Python不定时地收缩底层数组以节省内存，因此pop方法是摊销来计算的。（收缩数组也费时间，只是可能比较短）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "pop与del区别：pop默认删除最后一个，del没有默认；pop可以保存删除的元素，del直接删除，没得保存。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "remove方法仅删除一个值，找到了值，左边的需要遍历，右边的删除完值后要左移，所以一定是O(n)，至于摊销，是因为收缩数组造成的。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 5.4.2 Python的str类"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "将字符串中的空格、数字、标点符号去掉，我们想到的方法可以是将这些替换为空，也可以是遍历字符串，将字母提取出来形成一个新的字符串。在这个过程中，由于str不可变，如果每次直接`string += c`的话，n次操作O(n<sup>2</sup>)的运行时间；改进方法是先用可变的list存储，n次操作需要O(n)（摊销分析），最后join一下就好。由于是从一个可迭代的对象生成list或者另一个可迭代对象，所以可以用列表生成式简化代码并优化运行速度，如果用生成器（即圆括号）则更快。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 5.5 使用基于数组的序列"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "我们对array和Python中的list的理解有些狭隘，它们的元素不仅能是数字，也可以是字符，64位存储地址（也是数字），还可以是一个个的类的实例等。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "对类的私有变量，如果外界想获取，需要通过定义的方法进行return。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 5.5.2 插入排序"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "一句话总结：前面的元素有序，后面的元素无序，对后面的元素进行外层遍历，内层遍历为每个元素前面的元素，比较大小决定插入到什么位置，因此称为插入排序。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "def insert_sort(sequence):\n",
    "    j = 1\n",
    "    while j <= len(sequence)-1:\n",
    "        for i in range(j):\n",
    "            if sequence[i] >= sequence[j]:\n",
    "                sequence.insert(i, sequence[j])\n",
    "                del sequence[j+1]\n",
    "                break\n",
    "        j += 1\n",
    "    return sequence"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[2, 12, 21, 25, 35, 213, 563]\n",
      "[1, 11, 12, 14, 24, 43, 121, 123, 132]\n"
     ]
    }
   ],
   "source": [
    "print(insert_sort([2, 35, 12, 25, 563, 213, 21]))\n",
    "print(insert_sort([1, 24, 123, 12, 43, 14, 132, 121, 11]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "插入排序的效率可能受到insert方法的影响。但是如果将insert方法的效率也考虑进去，那么就相当于分析的是Python中的插入排序了。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 5.6 多维数据集"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在Python中，矩阵一般用list的list来存储。有时需要初始化一个list的list。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]\n",
      "[[1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0]]\n"
     ]
    }
   ],
   "source": [
    "mylist = [[0]*3]*10\n",
    "print(mylist)\n",
    "mylist[0][0] = 1\n",
    "print(mylist)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "上面这一种初始化方法的缺点是，经由\\*3的作用，每个元素list的3个元素都指向同一个int——0，经由\\*10的作用，每个元素都指向一个list的实例\\[0, 0, 0\\]，而list可变，所以改变第一个list会影响所有list。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]\n",
      "[[1, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]\n"
     ]
    }
   ],
   "source": [
    "mylist = [[0]*3 for i in range(10)]\n",
    "print(mylist)\n",
    "mylist[0][0] = 1\n",
    "print(mylist)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这个方法，使用了列表推导，在每一次循环的时候，都会创建一个不同的list实例，让每个元素都指向特定的实例。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 5.7 练习"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "R-5.1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Length:   0; Size in bytes:   64\n",
      "Length:   1; Size in bytes:   96\n",
      "Length:   2; Size in bytes:   96\n",
      "Length:   3; Size in bytes:   96\n",
      "Length:   4; Size in bytes:   96\n",
      "Length:   5; Size in bytes:  128\n",
      "Length:   6; Size in bytes:  128\n",
      "Length:   7; Size in bytes:  128\n",
      "Length:   8; Size in bytes:  128\n",
      "Length:   9; Size in bytes:  192\n",
      "Length:  10; Size in bytes:  192\n",
      "Length:  11; Size in bytes:  192\n",
      "Length:  12; Size in bytes:  192\n",
      "Length:  13; Size in bytes:  192\n",
      "Length:  14; Size in bytes:  192\n",
      "Length:  15; Size in bytes:  192\n",
      "Length:  16; Size in bytes:  192\n",
      "Length:  17; Size in bytes:  264\n",
      "Length:  18; Size in bytes:  264\n",
      "Length:  19; Size in bytes:  264\n",
      "Length:  20; Size in bytes:  264\n",
      "Length:  21; Size in bytes:  264\n",
      "Length:  22; Size in bytes:  264\n",
      "Length:  23; Size in bytes:  264\n",
      "Length:  24; Size in bytes:  264\n",
      "Length:  25; Size in bytes:  264\n",
      "Length:  26; Size in bytes:  344\n",
      "Length:  27; Size in bytes:  344\n",
      "Length:  28; Size in bytes:  344\n",
      "Length:  29; Size in bytes:  344\n",
      "Length:  30; Size in bytes:  344\n",
      "Length:  31; Size in bytes:  344\n",
      "Length:  32; Size in bytes:  344\n",
      "Length:  33; Size in bytes:  344\n",
      "Length:  34; Size in bytes:  344\n",
      "Length:  35; Size in bytes:  344\n",
      "Length:  36; Size in bytes:  432\n",
      "Length:  37; Size in bytes:  432\n",
      "Length:  38; Size in bytes:  432\n",
      "Length:  39; Size in bytes:  432\n",
      "Length:  40; Size in bytes:  432\n",
      "Length:  41; Size in bytes:  432\n",
      "Length:  42; Size in bytes:  432\n",
      "Length:  43; Size in bytes:  432\n",
      "Length:  44; Size in bytes:  432\n",
      "Length:  45; Size in bytes:  432\n",
      "Length:  46; Size in bytes:  432\n",
      "Length:  47; Size in bytes:  528\n",
      "Length:  48; Size in bytes:  528\n",
      "Length:  49; Size in bytes:  528\n"
     ]
    }
   ],
   "source": [
    "import sys\n",
    "\n",
    "data = []\n",
    "for k in range(50):\n",
    "    a = len(data)\n",
    "    b = sys.getsizeof(data)\n",
    "    print('Length: {0:3d}; Size in bytes: {1:4d}'.format(a, b))\n",
    "    data.append(None)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "R-5.2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0\n",
      "4\n",
      "8\n",
      "16\n",
      "25\n",
      "35\n",
      "46\n",
      "58\n",
      "72\n",
      "88\n",
      "106\n",
      "126\n",
      "148\n",
      "173\n"
     ]
    }
   ],
   "source": [
    "data = []\n",
    "b = sys.getsizeof(data)\n",
    "for k in range(200):\n",
    "    a = sys.getsizeof(data)\n",
    "    if a > b:\n",
    "        print(k-1)\n",
    "    b = a\n",
    "    data.append(None)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "R-5.3"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "删除元素时，内存空间会收缩，但不是立即收缩，而是以某种规律。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Length: 100; Size in bytes:  872\n",
      "Length:  99; Size in bytes:  872\n",
      "Length:  98; Size in bytes:  872\n",
      "Length:  97; Size in bytes:  872\n",
      "Length:  96; Size in bytes:  872\n",
      "Length:  95; Size in bytes:  872\n",
      "Length:  94; Size in bytes:  872\n",
      "Length:  93; Size in bytes:  872\n",
      "Length:  92; Size in bytes:  872\n",
      "Length:  91; Size in bytes:  872\n",
      "Length:  90; Size in bytes:  872\n",
      "Length:  89; Size in bytes:  872\n",
      "Length:  88; Size in bytes:  872\n",
      "Length:  87; Size in bytes:  872\n",
      "Length:  86; Size in bytes:  872\n",
      "Length:  85; Size in bytes:  872\n",
      "Length:  84; Size in bytes:  872\n",
      "Length:  83; Size in bytes:  872\n",
      "Length:  82; Size in bytes:  872\n",
      "Length:  81; Size in bytes:  872\n",
      "Length:  80; Size in bytes:  872\n",
      "Length:  79; Size in bytes:  872\n",
      "Length:  78; Size in bytes:  872\n",
      "Length:  77; Size in bytes:  872\n",
      "Length:  76; Size in bytes:  872\n",
      "Length:  75; Size in bytes:  872\n",
      "Length:  74; Size in bytes:  872\n",
      "Length:  73; Size in bytes:  872\n",
      "Length:  72; Size in bytes:  872\n",
      "Length:  71; Size in bytes:  872\n",
      "Length:  70; Size in bytes:  872\n",
      "Length:  69; Size in bytes:  872\n",
      "Length:  68; Size in bytes:  872\n",
      "Length:  67; Size in bytes:  872\n",
      "Length:  66; Size in bytes:  872\n",
      "Length:  65; Size in bytes:  872\n",
      "Length:  64; Size in bytes:  872\n",
      "Length:  63; Size in bytes:  872\n",
      "Length:  62; Size in bytes:  872\n",
      "Length:  61; Size in bytes:  872\n",
      "Length:  60; Size in bytes:  872\n",
      "Length:  59; Size in bytes:  872\n",
      "Length:  58; Size in bytes:  872\n",
      "Length:  57; Size in bytes:  872\n",
      "Length:  56; Size in bytes:  872\n",
      "Length:  55; Size in bytes:  872\n",
      "Length:  54; Size in bytes:  872\n",
      "Length:  53; Size in bytes:  872\n",
      "Length:  52; Size in bytes:  872\n",
      "Length:  51; Size in bytes:  872\n",
      "Length:  50; Size in bytes:  872\n",
      "Length:  49; Size in bytes:  552\n",
      "Length:  48; Size in bytes:  552\n",
      "Length:  47; Size in bytes:  552\n",
      "Length:  46; Size in bytes:  552\n",
      "Length:  45; Size in bytes:  552\n",
      "Length:  44; Size in bytes:  552\n",
      "Length:  43; Size in bytes:  552\n",
      "Length:  42; Size in bytes:  552\n",
      "Length:  41; Size in bytes:  552\n",
      "Length:  40; Size in bytes:  552\n",
      "Length:  39; Size in bytes:  552\n",
      "Length:  38; Size in bytes:  552\n",
      "Length:  37; Size in bytes:  552\n",
      "Length:  36; Size in bytes:  552\n",
      "Length:  35; Size in bytes:  552\n",
      "Length:  34; Size in bytes:  552\n",
      "Length:  33; Size in bytes:  552\n",
      "Length:  32; Size in bytes:  552\n",
      "Length:  31; Size in bytes:  552\n",
      "Length:  30; Size in bytes:  552\n",
      "Length:  29; Size in bytes:  368\n",
      "Length:  28; Size in bytes:  368\n",
      "Length:  27; Size in bytes:  368\n",
      "Length:  26; Size in bytes:  368\n",
      "Length:  25; Size in bytes:  368\n",
      "Length:  24; Size in bytes:  368\n",
      "Length:  23; Size in bytes:  368\n",
      "Length:  22; Size in bytes:  368\n",
      "Length:  21; Size in bytes:  368\n",
      "Length:  20; Size in bytes:  368\n",
      "Length:  19; Size in bytes:  368\n",
      "Length:  18; Size in bytes:  272\n",
      "Length:  17; Size in bytes:  272\n",
      "Length:  16; Size in bytes:  272\n",
      "Length:  15; Size in bytes:  272\n",
      "Length:  14; Size in bytes:  272\n",
      "Length:  13; Size in bytes:  272\n",
      "Length:  12; Size in bytes:  216\n",
      "Length:  11; Size in bytes:  216\n",
      "Length:  10; Size in bytes:  216\n",
      "Length:   9; Size in bytes:  216\n",
      "Length:   8; Size in bytes:  160\n",
      "Length:   7; Size in bytes:  160\n",
      "Length:   6; Size in bytes:  160\n",
      "Length:   5; Size in bytes:  128\n",
      "Length:   4; Size in bytes:  128\n",
      "Length:   3; Size in bytes:  112\n",
      "Length:   2; Size in bytes:  104\n",
      "Length:   1; Size in bytes:   96\n",
      "Length:   0; Size in bytes:   64\n"
     ]
    }
   ],
   "source": [
    "n = 101\n",
    "data = [None]*n\n",
    "for k in range(n):\n",
    "    data.pop()\n",
    "    a = len(data)\n",
    "    b = sys.getsizeof(data)\n",
    "    print('Length: {0:3d}; Size in bytes: {1:4d}'.format(a, b))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "R-5.5"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "摊销到每次操作为7个硬币。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "R-5.7"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "长度为n的数组，含1到n-1的整数，有一个整数是重复，如何找到？"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如果每个数都遍历其后的数，需要O(n<sup>2</sup>)，先进行排序，再进行前后比较，需要O(n+nlog n)即O(nlog n)。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [],
   "source": [
    "def quick_sort(sequence):\n",
    "    if len(sequence) == 1 or len(sequence) == 0:\n",
    "        return sequence\n",
    "    else:\n",
    "        greater_seq = []\n",
    "        less_seq = []\n",
    "        a = sequence[0]\n",
    "        del sequence[0]\n",
    "        for i in sequence:\n",
    "            if i >= a:\n",
    "                greater_seq.append(i)\n",
    "            else:\n",
    "                less_seq.append(i)\n",
    "        return quick_sort(less_seq) + [a] + quick_sort(greater_seq)\n",
    "\n",
    "def find_repeatition(sequence):\n",
    "    sequence = quick_sort(sequence)\n",
    "    for i in range(1, len(sequence)):\n",
    "        if sequence[i] == sequence[i-1]:\n",
    "            return sequence[i]\n",
    "    return False"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "9\n"
     ]
    }
   ],
   "source": [
    "print(find_repeatition([10, 9, 9, 8, 7, 6, 5, 4, 3, 2, 1]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "R-5.8"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.0\n",
      "0.04587864875793457\n",
      "0.10674262046813965\n"
     ]
    }
   ],
   "source": [
    "from time import time\n",
    "\n",
    "test_list = [k for k in range(1000000)]\n",
    "\n",
    "start = time()\n",
    "for i in range(100):\n",
    "    test_list.pop()\n",
    "print((time()-start))\n",
    "\n",
    "start = time()\n",
    "for i in range(100):\n",
    "    test_list.pop(500000)\n",
    "print((time()-start))\n",
    "\n",
    "start = time()\n",
    "for i in range(100):\n",
    "    test_list.pop(0)\n",
    "print((time()-start))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "R-5.11"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_sum(data):\n",
    "    result = 0\n",
    "    for i in data:\n",
    "        if i:\n",
    "            for j in i:\n",
    "                result += j\n",
    "    return result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "13\n"
     ]
    }
   ],
   "source": [
    "print(get_sum([[1, 2, 3], [2, 5], []]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "R-5.12"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_sum(data):\n",
    "    return sum((sum(k) for k in data))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "13\n"
     ]
    }
   ],
   "source": [
    "print(get_sum([[1, 2, 3], [2, 5], []]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "C-5.13"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Length:   4; Size in bytes:   96\n",
      "Length:   5; Size in bytes:  128\n",
      "Length:   6; Size in bytes:  128\n",
      "Length:   7; Size in bytes:  128\n",
      "Length:   8; Size in bytes:  128\n",
      "Length:   9; Size in bytes:  192\n",
      "Length:  10; Size in bytes:  192\n",
      "Length:  11; Size in bytes:  192\n",
      "Length:  12; Size in bytes:  192\n",
      "Length:  13; Size in bytes:  192\n",
      "Length:  14; Size in bytes:  192\n",
      "Length:  15; Size in bytes:  192\n",
      "Length:  16; Size in bytes:  192\n",
      "Length:  17; Size in bytes:  264\n",
      "Length:  18; Size in bytes:  264\n",
      "Length:  19; Size in bytes:  264\n",
      "Length:  20; Size in bytes:  264\n",
      "Length:  21; Size in bytes:  264\n",
      "Length:  22; Size in bytes:  264\n",
      "Length:  23; Size in bytes:  264\n",
      "Length:  24; Size in bytes:  264\n",
      "Length:  25; Size in bytes:  264\n",
      "Length:  26; Size in bytes:  344\n",
      "Length:  27; Size in bytes:  344\n",
      "Length:  28; Size in bytes:  344\n",
      "Length:  29; Size in bytes:  344\n",
      "Length:  30; Size in bytes:  344\n",
      "Length:  31; Size in bytes:  344\n",
      "Length:  32; Size in bytes:  344\n",
      "Length:  33; Size in bytes:  344\n",
      "Length:  34; Size in bytes:  344\n",
      "Length:  35; Size in bytes:  344\n",
      "Length:  36; Size in bytes:  432\n",
      "Length:  37; Size in bytes:  432\n",
      "Length:  38; Size in bytes:  432\n",
      "Length:  39; Size in bytes:  432\n",
      "Length:  40; Size in bytes:  432\n",
      "Length:  41; Size in bytes:  432\n",
      "Length:  42; Size in bytes:  432\n",
      "Length:  43; Size in bytes:  432\n",
      "Length:  44; Size in bytes:  432\n",
      "Length:  45; Size in bytes:  432\n",
      "Length:  46; Size in bytes:  432\n",
      "Length:  47; Size in bytes:  528\n",
      "Length:  48; Size in bytes:  528\n",
      "Length:  49; Size in bytes:  528\n",
      "Length:  50; Size in bytes:  528\n",
      "Length:  51; Size in bytes:  528\n",
      "Length:  52; Size in bytes:  528\n",
      "Length:  53; Size in bytes:  528\n"
     ]
    }
   ],
   "source": [
    "data = [0, 1, 2, 3]\n",
    "for k in range(50):\n",
    "    a = len(data)\n",
    "    b = sys.getsizeof(data)\n",
    "    print('Length: {0:3d}; Size in bytes: {1:4d}'.format(a, b))\n",
    "    data.append(None)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "C-5.14"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "import random\n",
    "\n",
    "def myshuffle(sequence):\n",
    "    result = []\n",
    "    while sequence:\n",
    "        r = random.randrange(0, len(sequence))\n",
    "        result.append(sequence[r])\n",
    "        del sequence[r]\n",
    "    return result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[7, 71, 52, 95, 89, 58, 43, 36, 73, 82, 53, 93, 3, 46, 96, 68, 66, 13, 80, 72, 9, 91, 10, 20, 84, 37, 4, 83, 79, 48, 12, 87, 30, 8, 26, 62, 55, 31, 5, 75, 60, 78, 34, 81, 94, 49, 44, 33, 50, 21, 69, 15, 28, 39, 97, 61, 77, 51, 88, 16, 57, 98, 63, 70, 85, 47, 35, 45, 2, 42, 41, 24, 76, 0, 23, 54, 99, 74, 92, 29, 86, 19, 27, 1, 14, 67, 90, 22, 11, 65, 59, 25, 38, 32, 40, 17, 56, 64, 18, 6]\n"
     ]
    }
   ],
   "source": [
    "print(myshuffle([k for k in range(100)]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "C-5.15"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "摊销即可。这个把握一下每次扩大数组与前一次扩大数组相差的元素个数就可以了。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "C-5.21"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.30354928970336914\n",
      "0.15617799758911133\n",
      "0.09373092651367188\n",
      "0.11195969581604004\n"
     ]
    }
   ],
   "source": [
    "n = 1000000\n",
    "## 第一种\n",
    "test_str = ''\n",
    "\n",
    "start = time()\n",
    "for i in range(n):\n",
    "    test_str += 'a'\n",
    "print(time()-start)\n",
    "\n",
    "## 第二种\n",
    "test_str = ''\n",
    "test_list = []\n",
    "\n",
    "start = time()\n",
    "for i in range(n):\n",
    "    test_list.append('a')\n",
    "test_str = ''.join(test_list)\n",
    "print(time()-start)\n",
    "\n",
    "## 第三种\n",
    "start = time()\n",
    "test_str = ''.join(['a' for k in range(n)])\n",
    "print(time()-start)\n",
    "\n",
    "## 第四种\n",
    "start = time()\n",
    "test_str = ''.join(('a' for k in range(n)))\n",
    "print(time()-start)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "C-5.22"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "列表长度为1000      ，extend运行时间为0.0       \n",
      "列表长度为1000      , append运行时间为0.0009989738464355469\n",
      "列表长度为10000     ，extend运行时间为0.0       \n",
      "列表长度为10000     , append运行时间为0.0009927749633789062\n",
      "列表长度为100000    ，extend运行时间为0.001994609832763672\n",
      "列表长度为100000    , append运行时间为0.027922868728637695\n",
      "列表长度为1000000   ，extend运行时间为0.01598834991455078\n",
      "列表长度为1000000   , append运行时间为0.16358160972595215\n"
     ]
    }
   ],
   "source": [
    "list_n = [1000, 10000, 100000, 1000000]\n",
    "\n",
    "for i in list_n:\n",
    "    \n",
    "    x = [k for k in range(i)]\n",
    "    y = [k for k in range(i)]\n",
    "    start = time()\n",
    "    x.extend(y)\n",
    "    print('列表长度为{0:<10}，extend运行时间为{1:<10}'.format(i, time()-start))\n",
    "    \n",
    "    x = [k for k in range(i)]\n",
    "    start = time()\n",
    "    for j in y:\n",
    "        x.append(j)\n",
    "    print('列表长度为{0:<10}, append运行时间为{1:<10}'.format(i, time()-start))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "C-5.23"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.legend.Legend at 0x1e1bdb8c978>"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "\n",
    "list_n = [100000, 200000, 300000, 400000, 500000, 600000]\n",
    "time_x, time_y = [], []\n",
    "\n",
    "for i in list_n:\n",
    "    x = []\n",
    "    y = []\n",
    "    \n",
    "    start = time()\n",
    "    x = [k*k for k in range(i)]\n",
    "    time_x.append(time()-start)\n",
    "    \n",
    "    start = time()\n",
    "    for k in range(i):\n",
    "        y.append(k*k)\n",
    "    time_y.append(time()-start)\n",
    "\n",
    "plt.plot(list_n, time_x, label='list_comprehension')\n",
    "plt.plot(list_n, time_y, label='loop_append')\n",
    "\n",
    "plt.legend()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "C-5.24"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.legend.Legend at 0x1e1abaff438>"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "list_n = [100000, 200000, 300000, 400000, 500000, 600000, 700000, 800000, 900000]\n",
    "time_x, time_y, time_z = [], [], []\n",
    "\n",
    "for i in list_n:\n",
    "    \n",
    "    x = [k for k in range(i)]\n",
    "    \n",
    "    start = time()\n",
    "    x.remove(0)\n",
    "    time_x.append(time()-start)\n",
    "    \n",
    "    start = time()\n",
    "    x.remove(i/2)\n",
    "    time_y.append(time()-start)\n",
    "    \n",
    "    start = time()\n",
    "    x.remove(i-3)\n",
    "    time_z.append(time()-start)\n",
    "\n",
    "plt.plot(list_n, time_x, label='beginning')\n",
    "plt.plot(list_n, time_y, label='center')\n",
    "plt.plot(list_n, time_z, label='ending')\n",
    "\n",
    "plt.legend()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "C-5.25"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "要remove多个，重复使用remove可能效率较低，因为每次删除一个都要遍历前面的和移动后面的，最坏的情况下时间复杂度是O(n<sup>2</sup>)。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [],
   "source": [
    "def remove_all(sequence, value):\n",
    "    result = []\n",
    "    for k in sequence:\n",
    "        if k != value:\n",
    "            result.append(k)\n",
    "    return result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[2, 3, 3, 2]\n"
     ]
    }
   ],
   "source": [
    "print(remove_all([1, 2, 3, 1, 1, 3, 2, 1], 1))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "C-5.26"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "找出5个重复的元素，思路和之前一样，快速排序+遍历搞定。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "C-5.29"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "只能想出一个双层循环进行遍历的方法，不知道有没有更加高效的方法。"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.2"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": false,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  },
  "varInspector": {
   "cols": {
    "lenName": 16,
    "lenType": 16,
    "lenVar": 40
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
